/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package com.plian.system.service.im.impl;

import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.plian.Tools.*;
import com.plian.system.bean.im.EffectiveInvestmentExcelBean;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.dto.im.BaseInvestmentExecutionDTO;
import com.plian.system.entity.im.EffectiveInvestment;
import com.plian.system.entity.im.ExecutionProjectSituation;
import com.plian.system.entity.im.MainProjectSituation;
import com.plian.system.mapper.im.EffectiveInvestmentMapper;
import com.plian.system.mybatis.base.BaseServiceImpl;
import com.plian.system.service.im.IEffectiveInvestmentService;
import com.plian.system.service.im.IExecutionProjectSituationService;
import com.plian.system.service.im.IMainProjectSituationService;
import com.plian.system.service.im.IProjectInfoService;
import com.plian.system.vo.im.*;
import com.plian.system.vo.report.HeaderVO;
import com.plian.system.vo.report.ReportReturnVO;
import com.plian.system.vo.report.ReportVO;
import com.plian.system.wrapper.im.ExecutionProjectSituationWrapper;
import com.plian.system.wrapper.im.MainProjectSituationWrapper;
import com.plian.system.wrapper.im.ProjectInfoWrapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author
 * @since 2019-09-27
 */
@Slf4j
@Service
@AllArgsConstructor
public class EffectiveInvestmentServiceImpl extends BaseServiceImpl<EffectiveInvestmentMapper, EffectiveInvestment> implements IEffectiveInvestmentService {

	private IMainProjectSituationService mainProjectSituationService;

	private IExecutionProjectSituationService executionProjectSituationService;

	private MainProjectSituationWrapper mainProjectSituationWrapper;

	private ExecutionProjectSituationWrapper executionProjectSituationWrapper;

	private IProjectInfoService projectInfoService;

	private ProjectInfoWrapper projectInfoWrapper;

	@Override
	public boolean saveOrUpdate(EffectiveInvestment effectiveInvestment) {

		if (!Optional.ofNullable(effectiveInvestment.getStatus()).isPresent()) {
			effectiveInvestment.setStatus(FormStatusConstant.UNREVIEWED);
		}
		return super.saveOrUpdate(effectiveInvestment);
	}

	@Override
	@Transactional(rollbackFor=RuntimeException.class)
	public boolean deleteLogic(List<Long> ids) {
		for (Long id : ids) {
			EffectiveInvestment effectiveInvestment = getById(id);
			if (effectiveInvestment == null) {
				return false;
			} else if (effectiveInvestment.getStatus() != null &&
					(effectiveInvestment.getStatus() != FormStatusConstant.STASH && effectiveInvestment.getStatus() != FormStatusConstant.UNREVIEWED)) {
				return false;
			}
		}

		boolean result = super.deleteLogic(ids);
		if (result){
			mainProjectSituationService.deleteByParentId(ids);
			executionProjectSituationService.deleteByParentId(ids);
		}
		return result;
	}

	@Override
	public boolean submit(EffectiveInvestment effectiveInvestment) {
		boolean result = saveOrUpdate(effectiveInvestment);
		if (result){
			List<MainProjectSituation> mainProjectSituations = effectiveInvestment.getMainProjectSituations();
			if (CollectionUtil.isNotEmpty(mainProjectSituations)){
				for (MainProjectSituation mainProjectSituation : mainProjectSituations){
					if (mainProjectSituation.getId() != null &&
							Optional.ofNullable(mainProjectSituation.getIsDeleted()).isPresent() && mainProjectSituation.getIsDeleted().intValue() == 1) {
						mainProjectSituationService.removeById(mainProjectSituation.getId());
					}else {
						mainProjectSituation.setEffectiveInvestmentId(effectiveInvestment.getId());
						mainProjectSituationService.saveOrUpdate(mainProjectSituation);
					}
				}
			}

			List<ExecutionProjectSituation> fixedProjectSituations = effectiveInvestment.getFixedProjectSituations();
			if (CollectionUtil.isNotEmpty(fixedProjectSituations)){
				for (ExecutionProjectSituation projectSituation : fixedProjectSituations){
					if (projectSituation.getId() != null &&
							Optional.ofNullable(projectSituation.getIsDeleted()).isPresent() && projectSituation.getIsDeleted().intValue() == 1) {
						executionProjectSituationService.removeById(projectSituation.getId());
					}else {
						projectSituation.setEffectiveInvestmentId(effectiveInvestment.getId());
						projectSituation.setProjectType(2);
						executionProjectSituationService.saveOrUpdate(projectSituation);
					}
				}
			}

			List<ExecutionProjectSituation> stakeProjectSituations = effectiveInvestment.getStakeProjectSituations();
			if (CollectionUtil.isNotEmpty(stakeProjectSituations)){
				for (ExecutionProjectSituation projectSituation : stakeProjectSituations){
					if (projectSituation.getId() != null &&
							Optional.ofNullable(projectSituation.getIsDeleted()).isPresent() && projectSituation.getIsDeleted().intValue() == 1) {
						executionProjectSituationService.removeById(projectSituation.getId());
					}else {
						projectSituation.setEffectiveInvestmentId(effectiveInvestment.getId());
						projectSituation.setProjectType(1);
						executionProjectSituationService.saveOrUpdate(projectSituation);
					}
				}
			}

		}

		return result;
	}

	@Override
	public EffectiveInvestmentVO getDetailPd(EffectiveInvestmentVO effectiveInvestmentVO) {
		if(!Optional.ofNullable(effectiveInvestmentVO).isPresent()){
			return null;
		}

		effectiveInvestmentVO.setMainProjectSituationVOS(mainProjectSituationWrapper
				.entityToVO(mainProjectSituationService.list(new LambdaQueryWrapper<MainProjectSituation>()
						.eq(MainProjectSituation::getEffectiveInvestmentId, effectiveInvestmentVO.getId()))));

		effectiveInvestmentVO.setStakeProjectSituationVOS(executionProjectSituationWrapper
				.entityToVO(executionProjectSituationService.list(new LambdaQueryWrapper<ExecutionProjectSituation>()
						.eq(ExecutionProjectSituation::getEffectiveInvestmentId, effectiveInvestmentVO.getId())
						.eq(ExecutionProjectSituation::getProjectType, 1))));

		effectiveInvestmentVO.setFixedProjectSituationVOS(executionProjectSituationWrapper
				.entityToVO(executionProjectSituationService.list(new LambdaQueryWrapper<ExecutionProjectSituation>()
						.eq(ExecutionProjectSituation::getEffectiveInvestmentId, effectiveInvestmentVO.getId())
						.eq(ExecutionProjectSituation::getProjectType, 2))));



		return effectiveInvestmentVO;
	}

	@Override
	public EffectiveInvestmentVO getLastMainInfos(Long id) {
		List<MainProjectSituation> mainProjectSituations = mainProjectSituationService.list(
				new LambdaQueryWrapper<MainProjectSituation>().eq(MainProjectSituation::getEffectiveInvestmentId, id));
		if (CollectionUtil.isNotEmpty(mainProjectSituations)){
			for (MainProjectSituation mainProjectSituation : mainProjectSituations){
				mainProjectSituation.setId(null);
				mainProjectSituation.setCreateUser(null);
				mainProjectSituation.setCreateTime(null);
				mainProjectSituation.setUpdateUser(null);
				mainProjectSituation.setUpdateTime(null);
				mainProjectSituation.setLastCompleteInvestment(BigDecimalUtil.add(mainProjectSituation.getLastCompleteInvestment(),
						(mainProjectSituation.getCompleteInvestment())));
				mainProjectSituation.setCompleteInvestment(new BigDecimal(0));
			}
		}
		EffectiveInvestmentVO effectiveInvestmentVO = new EffectiveInvestmentVO();
		effectiveInvestmentVO.setMainProjectSituationVOS(mainProjectSituationWrapper.entityToVO(mainProjectSituations));

		List<ProjectInfoVO> projectInfos=projectInfoWrapper.entityToVO(projectInfoService.list());
		//项目对应的
		Map<Long,ProjectInfoVO> projectInfoVOMap=projectInfos.stream().collect(Collectors.toMap(record->record.getId(),record->record));
		List<ExecutionProjectSituation> stakeProjectSituations = executionProjectSituationService
				.list(new LambdaQueryWrapper<ExecutionProjectSituation>()
				.eq(ExecutionProjectSituation::getEffectiveInvestmentId, id)
				.eq(ExecutionProjectSituation::getProjectType, 1));
		if (CollectionUtil.isNotEmpty(stakeProjectSituations)){
			for (ExecutionProjectSituation projectSituation : stakeProjectSituations){
				projectSituation.setId(null);
				projectSituation.setCreateUser(null);
				projectSituation.setCreateTime(null);
				projectSituation.setUpdateUser(null);
				projectSituation.setUpdateTime(null);
				projectSituation.setLastCompleteInvestment(BigDecimalUtil.add(projectSituation.getLastCompleteInvestment(),
						(projectSituation.getCompleteInvestment())));
				projectSituation.setCompleteInvestment(new BigDecimal(0));
			}
		}

		List<ExecutionProjectSituationVO> stakeProjectSituationVOS=executionProjectSituationWrapper.entityToVO(stakeProjectSituations);
		for(ExecutionProjectSituationVO e:stakeProjectSituationVOS){
			Long projectId=e.getProjectId();
			//对应项目性质从项目信息里面拿
			if(projectInfoVOMap.containsKey(projectId)){
				ProjectInfoVO projectInfoVO=projectInfoVOMap.get(projectId);
				e.setProjectNatureName(projectInfoVO.getProjectNatureName());
				e.setProjectNatureId(projectInfoVO.getProjectNatureId());
			}
		}
		effectiveInvestmentVO.setStakeProjectSituationVOS(stakeProjectSituationVOS);



		List<ExecutionProjectSituation> fixedProjectSituations = executionProjectSituationService
				.list(new LambdaQueryWrapper<ExecutionProjectSituation>()
						.eq(ExecutionProjectSituation::getEffectiveInvestmentId, id)
						.eq(ExecutionProjectSituation::getProjectType, 2));
		if (CollectionUtil.isNotEmpty(fixedProjectSituations)){
			for (ExecutionProjectSituation projectSituation : fixedProjectSituations){
				projectSituation.setId(null);
				projectSituation.setCreateUser(null);
				projectSituation.setCreateTime(null);
				projectSituation.setUpdateUser(null);
				projectSituation.setUpdateTime(null);
				projectSituation.setLastCompleteInvestment(BigDecimalUtil.add(projectSituation.getLastCompleteInvestment(),
						(projectSituation.getCompleteInvestment())));
				projectSituation.setCompleteInvestment(new BigDecimal(0));
			}
		}
		List<ExecutionProjectSituationVO> fixedProjectSituationVOS=executionProjectSituationWrapper.entityToVO(fixedProjectSituations);
		for(ExecutionProjectSituationVO e:fixedProjectSituationVOS){
			Long projectId=e.getProjectId();
			//对应项目性质从项目信息里面拿
			if(projectInfoVOMap.containsKey(projectId)){
				ProjectInfoVO projectInfoVO=projectInfoVOMap.get(projectId);
				e.setProjectNatureName(projectInfoVO.getProjectNatureName());
				e.setProjectNatureId(projectInfoVO.getProjectNatureId());
			}
		}
		effectiveInvestmentVO.setFixedProjectSituationVOS(fixedProjectSituationVOS);
		return effectiveInvestmentVO;
	}

	@Override
	public List<InvestmentMonthSummaryVO> summary(BaseInvestmentExecutionDTO baseInvestmentExecutionDTO) {

		/**
		 * 填报年月为空时默认为当前月份
		 */
		String filingMonth = baseInvestmentExecutionDTO.getFilingMonth();
		if (StringUtil.isBlank(filingMonth)){
			filingMonth = DateUtil.format(DateUtil.now(), DateUtil.PATTERN_MONTH);
		}
		String filingYear = filingMonth.split(StringPool.DASH)[0];
		List<InvestmentMonthSummaryVO> summaryVOS = baseMapper.summary(baseInvestmentExecutionDTO.getFillingUnitIds(), filingYear, filingMonth);
		InvestmentMonthSummaryVO end = InvestmentMonthSummaryVO.builder().filingUnitName("合计").build();
		if (CollectionUtil.isNotEmpty(summaryVOS)){
			summaryVOS = summaryVOS.stream().filter(summaryVO -> {
				if (summaryVO.getPlanInvestmentTotal() == null
						&& summaryVO.getFixedPlanInvestment() == null
						&& summaryVO.getStakePlanInvestment() == null
						&&summaryVO.getAllCompleteInvestment() == null
						&& summaryVO.getAllCompleteFixedInvestment() == null
						&& summaryVO.getAllCompleteEquityInvestment() == null){
					return false;
				}
				return true;
			}).collect(Collectors.toList());
			for (int i = 0; i < summaryVOS.size(); i++){
				InvestmentMonthSummaryVO vo = summaryVOS.get(i);
				vo.setIndex(String.valueOf(i + 1));
				vo.setCompleteProportion(BigDecimalUtil.divide(vo.getAllCompleteInvestment(), vo.getPlanInvestmentTotal(), 2, BigDecimal.ROUND_HALF_UP, 100));
				end.setPlanInvestmentTotal(BigDecimalUtil.add(end.getPlanInvestmentTotal(), vo.getPlanInvestmentTotal()));
				end.setFixedPlanInvestment(BigDecimalUtil.add(end.getFixedPlanInvestment(), vo.getFixedPlanInvestment()));
				end.setStakePlanInvestment(BigDecimalUtil.add(end.getStakePlanInvestment(), vo.getStakePlanInvestment()));
				end.setAllCompleteInvestment(BigDecimalUtil.add(end.getAllCompleteInvestment(), vo.getAllCompleteInvestment()));
				end.setAllCompleteFixedInvestment(BigDecimalUtil.add(end.getAllCompleteFixedInvestment(), vo.getAllCompleteFixedInvestment()));
				end.setAllCompleteEquityInvestment(BigDecimalUtil.add(end.getAllCompleteEquityInvestment(), vo.getAllCompleteEquityInvestment()));

			}
//			summaryVOS.sort(Comparator.comparing(InvestmentMonthSummaryVO::getCompleteProportion).reversed());
			end.setCompleteProportion(BigDecimalUtil.divide(end.getAllCompleteInvestment(), end.getPlanInvestmentTotal(), 2, BigDecimal.ROUND_HALF_UP, 100));
			summaryVOS.add(end);
		}

		return summaryVOS;
	}

	@Override
	public void write(EffectiveInvestment effectiveInvestment, ExcelWriter excelWriter, WriteSheet writeSheet, FillConfig fillConfig) {
		EffectiveInvestmentExcelBean effectiveInvestmentExcelBean = new EffectiveInvestmentExcelBean();
		BeanUtils.copyProperties(effectiveInvestment, effectiveInvestmentExcelBean);
		if (Optional.ofNullable(effectiveInvestment.getFilingDate()).isPresent()){
			effectiveInvestmentExcelBean.setFilingDateStr(DateUtil.formatDate(effectiveInvestment.getFilingDate()));
		}
		excelWriter.fill(effectiveInvestmentExcelBean, fillConfig, writeSheet);

//		mainProjectSituationService.write(mainProjectSituationService.list(new LambdaQueryWrapper<MainProjectSituation>()
//				.eq(MainProjectSituation::getEffectiveInvestmentId, effectiveInvestment.getId())), excelWriter, writeSheet, fillConfig);

		executionProjectSituationService.write(effectiveInvestment.getId(), excelWriter, writeSheet, fillConfig);
	}

	@Override
	public boolean deleteByParentId(List<Long> ids) {
		LambdaQueryWrapper<EffectiveInvestment> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.in(EffectiveInvestment::getBaseInvestmentExecutionId, ids);
		List<EffectiveInvestment> effectiveInvestments = list(queryWrapper);
		if (CollectionUtil.isNotEmpty(effectiveInvestments)){
			return deleteLogic(effectiveInvestments.stream().map(EffectiveInvestment::getId).collect(Collectors.toList()));
		}
		return true;
	}

	@Override
	public ReportReturnVO effectiveSummary(BaseInvestmentExecutionDTO baseInvestmentExecutionDTO) {
		baseInvestmentExecutionDTO.setFilingMonth(baseInvestmentExecutionDTO.getFillingMonth());
		List<InvestmentMonthSummaryVO> data = summary(baseInvestmentExecutionDTO);
		List<EffectiveInvestmentSummaryVO> results = new ArrayList<>();
		if (CollectionUtil.isNotEmpty(data)){
			InvestmentMonthSummaryVO vo = data.get(0);
			EffectiveInvestmentSummaryVO total = EffectiveInvestmentSummaryVO.builder().sumName("有效投资合计")
					.planInvestmentTotal(vo.getPlanInvestmentTotal()).completeInvestment(vo.getAllCompleteInvestment())
					.completeProportion(BigDecimalUtil.divide(vo.getAllCompleteInvestment(), vo.getPlanInvestmentTotal(), 2, BigDecimal.ROUND_HALF_UP, 100)).build();
			results.add(total);
			EffectiveInvestmentSummaryVO stake = EffectiveInvestmentSummaryVO.builder().index("一").sumName("股权投资（小计）")
					.planInvestmentTotal(vo.getStakePlanInvestment()).completeInvestment(vo.getAllCompleteEquityInvestment())
					.completeProportion(BigDecimalUtil.divide(vo.getAllCompleteEquityInvestment(), vo.getStakePlanInvestment(), 2, BigDecimal.ROUND_HALF_UP, 100)).build();
			results.add(stake);
			EffectiveInvestmentSummaryVO fixed = EffectiveInvestmentSummaryVO.builder().index("二").sumName("固定资产投资（小计）")
					.planInvestmentTotal(vo.getFixedPlanInvestment()).completeInvestment(vo.getAllCompleteFixedInvestment())
					.completeProportion(BigDecimalUtil.divide(vo.getAllCompleteFixedInvestment(), vo.getFixedPlanInvestment(), 2, BigDecimal.ROUND_HALF_UP, 100)).build();
			results.add(fixed);
		}

		ReportReturnVO reportReturnVO = new ReportReturnVO();
		ReportVO reportVO = new ReportVO();
		reportVO
				.addHeader(HeaderVO.builder().key("index").title("序号").build())
				.addHeader(HeaderVO.builder().key("sumName").title("项目名称和投资企业名称").build())
				.addHeader(HeaderVO.builder().key("planInvestmentTotal").title("计划投资额").build())
				.addHeader(HeaderVO.builder().key("completeInvestment").title("实际完成额").build())
				.addHeader(HeaderVO.builder().key("completeProportion").title("实际完成率（%）").build());
		reportVO.setData(results);
		reportReturnVO.setGrids(reportVO);
		return reportReturnVO;
	}

	@Override
	public String check(EffectiveInvestment effectiveInvestment) {
		String number = effectiveInvestment.getNumber();
		if (StringUtil.isNotBlank(number) && number.length() > 20){
			return "联系电话过长";
		}
		return null;
	}

}
